package com.hgxd.mc.collection;

import com.hgxd.mc.entity.StiffNessData;
import com.hgxd.mc.utils.ByteToHexStrUtil;
import com.hgxd.mc.utils.GetValidRespondMesUtil;
import com.hgxd.mc.utils.ReversByteStringUtil;
import com.sun.xml.internal.bind.v2.TODO;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class StiffNessDataGet {

    private static final int RECEIVE_TIMEOUT = 5000;
    private static final int REQUEST_SIZE = 21;
    private static final int RESPOND_SIZE = 23;

    private String ipAddress;
    private int port;

    private Socket socket;
    private DataInputStream input;
    private DataOutputStream output;

    public static void main(String[] args) throws IOException {

        StiffNessDataGet mcSteelAngleGet = new StiffNessDataGet("192.168.1.10", 5000);

        if (mcSteelAngleGet.connect()) {
            byte[] address = new byte[]{0x00, 0x10, 0x00};
            byte[] number = new byte[]{0x00, 0x01};
            byte tab = (byte) 0xB4;

            String respondMess = mcSteelAngleGet.sendMcReadRequest(address, tab, number);

            List<List<String>> resultStrLists = analysisReadRespond(respondMess);

            mcSteelAngleGet.getValues(resultStrLists);
//            Thread.sleep(600);

            mcSteelAngleGet.disconnect();
        } else {
            System.out.println("连接失败！！！");
        }


    }

    public StiffNessDataGet(String ipAddress, int port) {
        this.ipAddress = ipAddress;
        this.port = port;
    }

    /**
     * Tcp连接
     */
    public boolean connect() {
        try {
            socket = new Socket(ipAddress, port);
            input = new DataInputStream(socket.getInputStream());
            output = new DataOutputStream(socket.getOutputStream());
            socket.setSoTimeout(RECEIVE_TIMEOUT);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * Tcp关闭连接
     */
    public void disconnect() {
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送数据读取的报文
     *
     * @param addressStart 寄存器起始地址
     * @param Tab          寄存器标识
     * @param number       请求寄存器地址数量
     */
    public String sendMcReadRequest(byte[] addressStart, byte Tab, byte[] number) throws IOException {

//        // 创建输入流和输出流
//        InputStream inputStream = socket.getInputStream();
//        OutputStream outputStream = socket.getOutputStream();

//         byte[] message = new byte[]{0x50, 0x00, 0x00, (byte) 0xFF, (byte) 0xFF, 0x03, 0x00
//         , 0x0c, 0x00, 0x10, 0x00, 0x01, 0x04, 0x00, 0x00, (byte) 0x00, (byte) 0x10
//         , 0x00, (byte) 0xB4, 0x2B, 0x00};

        //构造请求报文
        byte[] requestMess = new byte[REQUEST_SIZE];

        // 副头部
        requestMess[0] = (byte) 0x50;
        requestMess[1] = (byte) 0x00;

        // 网络编号
        requestMess[2] = (byte) 0x00;

        // 可编程控制器编号
        requestMess[3] = (byte) 0xFF;

        // 请求目标模块 I/O 编号
        requestMess[4] = (byte) 0xFF;
        requestMess[5] = (byte) 0x03;

        // 请求目标模块站号
        requestMess[6] = (byte) 0x00;

        // 请求数据长度
        requestMess[7] = (byte) 0x0c;
        requestMess[8] = (byte) 0x00;

        // CPU监视定时器
        requestMess[9] = (byte) 0x10;
        requestMess[10] = (byte) 0x00;

        // 读取指令
        requestMess[11] = (byte) 0x01;
        requestMess[12] = (byte) 0x04;

        // 子指令
        requestMess[13] = (byte) 0x00;
        requestMess[14] = (byte) 0x00;

        //请求数据部分（自定义修改）
        //寄存器起始地址
        requestMess[15] = addressStart[2];
        requestMess[16] = addressStart[1];
        requestMess[17] = addressStart[0];

        //寄存器标识
        requestMess[18] = Tab;

        //寄存器数量
        requestMess[19] = number[1];
        requestMess[20] = number[0];

//        byte[] message = new byte[]{0x50, 0x00, 0x00, (byte) 0xFF, (byte) 0xFF, 0x03, 0x00
//                , 0x0E, 0x00, 0x10, 0x00, 0x01, 0x14, 0x00, 0x00, (byte) 0x0A, (byte) 0x10
//                , 0x00, (byte) 0xB4, 0x01, 0x00, 0x0C, 0x00};

        // 发送请求数据
        output.write(requestMess);

        // 接收响应数据
        byte[] respondBuffer = new byte[1024];
        // 响应报文长度
        int lengthReceived = input.read(respondBuffer);

//        byte[] respondBuff = new byte[lengthReceived];
//        for (int i = 0; i < lengthReceived; i++) {
//            respondBuff[i] = respondBuffer[i];
//        }

        byte[] realRespondBuffer = GetValidRespondMesUtil.getValidRespondMes(respondBuffer, lengthReceived);

        //        //输入输出流关闭
//        output.close();
//        input.close();

        return ByteToHexStrUtil.bytesToHexString(realRespondBuffer);
    }

    /**
     * 发送写数据的报文
     */
    public String sendMcWriteRequest(byte[] addressStart, byte Tab, byte[] value) throws IOException {

        // 创建输入流和输出流
        InputStream inputStream = socket.getInputStream();
        OutputStream outputStream = socket.getOutputStream();

//        byte[] message = new byte[]{0x50, 0x00, 0x00, (byte) 0xFF, (byte) 0xFF, 0x03, 0x00
//                , 0x0E, 0x00, 0x10, 0x00, 0x01, 0x14, 0x00, 0x00, (byte) 0x0A, (byte) 0x10
//                , 0x00, (byte) 0xB4, 0x01, 0x00, 0x0C, 0x00};

        //构造请求报文
        byte[] requestMess = new byte[RESPOND_SIZE];

        // 副头部
        requestMess[0] = (byte) 0x50;
        requestMess[1] = (byte) 0x00;

        // 网络编号
        requestMess[2] = (byte) 0x00;

        // 可编程控制器编号
        requestMess[3] = (byte) 0xFF;

        // 请求目标模块 I/O 编号
        requestMess[4] = (byte) 0xFF;
        requestMess[5] = (byte) 0x03;

        // 请求目标模块站号
        requestMess[6] = (byte) 0x00;

        // 请求数据长度
        requestMess[7] = (byte) 0x0E;
        requestMess[8] = (byte) 0x00;

        // CPU监视定时器
        requestMess[9] = (byte) 0x10;
        requestMess[10] = (byte) 0x00;

        // 读取指令
        requestMess[11] = (byte) 0x01;
        requestMess[12] = (byte) 0x14;

        // 子指令
        requestMess[13] = (byte) 0x00;
        requestMess[14] = (byte) 0x00;

        //请求数据部分（自定义修改）
        //寄存器起始地址
        requestMess[15] = addressStart[2];
        requestMess[16] = addressStart[1];
        requestMess[17] = addressStart[0];

        //寄存器标识
        requestMess[18] = Tab;

        //寄存器数量
        requestMess[19] = 0x01;
        requestMess[20] = 0x00;

        requestMess[21] = value[1];
        requestMess[22] = value[0];

        // 发送请求数据
        outputStream.write(requestMess);

        // 接收响应数据
        byte[] buffer = new byte[1024];
        int lengthReceived = inputStream.read(buffer);

//        //输入输出流关闭
//        inputStream.close();
//        outputStream.close();

        return new String(buffer, 0, lengthReceived, StandardCharsets.US_ASCII);
    }

    /**
     * 从字符串报文中截取各个值的字符串
     */
    public static List<List<String>> analysisReadRespond(String respondMess) {

        String messLenHexStr = respondMess.substring(14, 18);
        String reLenHexStr = ReversByteStringUtil.reByteStr(messLenHexStr);
        int lenData = Integer.parseInt(reLenHexStr, 16);

        // 数据长度定义(单位：word)
        int indexStart = 22;
        int lenOne = 1;
        int lenTwo = 2;
        int lenSeven = 7;
        int lenTwenty = 12;
        int lenFifteen = 15;
        int lenTrans = 4;   // 1word = 2btye = 4hex


        String workStationAbleStr = respondMess.substring(indexStart, (indexStart + lenOne * lenTrans));
        String storeStatusStr = respondMess.substring((indexStart + lenOne * lenTrans), (indexStart + lenOne * 2 * lenTrans));
        String productTypeStr = respondMess.substring((indexStart + 2 * lenTrans), (indexStart + (lenOne * 2 + lenSeven) * lenTrans));
        String steelTypeStr = respondMess.substring((indexStart + (lenOne * 2 + lenSeven) * lenTrans), (indexStart + (lenOne * 2 + lenSeven + lenTwenty) * lenTrans));
        String twoDimCodeStr = respondMess.substring((indexStart + (lenOne * 2 + lenSeven + lenTwenty) * lenTrans), (indexStart + (lenOne * 2 + lenSeven + lenTwenty + lenFifteen) * lenTrans));
        String totalStatusStr = respondMess.substring((indexStart + (lenOne * 2 + lenSeven + lenTwenty + lenFifteen) * lenTrans), (indexStart + (lenOne * 2 + lenSeven + lenTwenty + lenFifteen + lenOne) * lenTrans));

        List<String> onePartList = new ArrayList<>();
        onePartList.add(workStationAbleStr);
        onePartList.add(storeStatusStr);
        onePartList.add(productTypeStr);
        onePartList.add(steelTypeStr);
        onePartList.add(twoDimCodeStr);
        onePartList.add(totalStatusStr);

        // AB
        int indexABStart = indexStart + (lenOne * 2 + lenSeven + lenTwenty + lenFifteen + lenOne) * lenTrans;
        List<String> listABValueStr = twoPointValue(respondMess, indexABStart, indexABStart + lenTwo * 8 * lenTrans);

        // BC
        int indexBCStart = indexABStart + lenTwo * 8 * lenTrans + lenOne * lenTrans;
        listABValueStr.add(respondMess.substring(indexABStart + lenTwo * 8 * lenTrans, indexBCStart));

        List<String> listBCValueStr = twoPointValue(respondMess, indexBCStart, indexBCStart + lenTwo * 8 * lenTrans);

        // CD
        int indexCDStart = indexBCStart + lenTwo * 8 * lenTrans + lenOne * lenTrans;
        listBCValueStr.add(respondMess.substring(indexBCStart + lenTwo * 8 * lenTrans, indexCDStart));

        List<String> listCDValueStr = twoPointValue(respondMess, indexCDStart, indexCDStart + lenTwo * 8 * lenTrans);

        // AD
        int indexADStart = indexCDStart + lenTwo * 8 * lenTrans + lenOne * lenTrans;
        listCDValueStr.add(respondMess.substring(indexCDStart + lenTwo * 8 * lenTrans, indexADStart));

        List<String> listADValueStr = twoPointValue(respondMess, indexADStart, indexADStart + lenTwo * 8 * lenTrans);

        int indexADEnd = indexADStart + lenTwo * 8 * lenTrans + lenOne * lenTrans;
        listADValueStr.add(respondMess.substring(indexADStart + lenTwo * 8 * lenTrans, indexADEnd));

        // 相位角
        List<String> listPhaseAngleStr = twoPointValue(respondMess, indexADStart, indexADEnd + lenTwo * 3 * lenTrans);

        List<List<String>> analysisResultLists = new ArrayList<>();
        analysisResultLists.add(onePartList);
        analysisResultLists.add(listABValueStr);
        analysisResultLists.add(listBCValueStr);
        analysisResultLists.add(listCDValueStr);
        analysisResultLists.add(listADValueStr);
        analysisResultLists.add(listPhaseAngleStr);

        return analysisResultLists;
    }

    /**
     * 将字符串转化为数值
     */
    public void getValues(List<List<String>> resultLists) {

        // 第一部分数值转化
        List<String> onePartList = resultLists.get(0);

        int workAble = Integer.parseInt(onePartList.get(0), 16);
        int storeStatue = Integer.parseInt(onePartList.get(1), 16);

        List<String> oneHextoASCII = onePartList.subList(2, 5);
        List<String> typeASCIIList = HexStrToASCII(oneHextoASCII);

        int totalStatue = Integer.parseInt(onePartList.get(5));

        System.out.println("工位操作使能:" + workAble);
        System.out.println("存储状态:" + storeStatue);
        System.out.println("总状态:" + totalStatue);
        System.out.println("产品型号\t\t钢刻号\t\t二维码");
        for (String s : typeASCIIList) {
            System.out.print(s + "  ");
        }

        // 第二部分数值获取（AB）
        List<Float> listABValues = HexStrToFloat(resultLists.get(1));

        // 第三部分数值获取（BC）
        List<Float> listBCValues = HexStrToFloat(resultLists.get(2));

        // 第四部分数值获取（CD）
        List<Float> listCDValues = HexStrToFloat(resultLists.get(3));

        // 第五部分数值获取（AD）
        List<Float> listADValues = HexStrToFloat(resultLists.get(4));

        printValue(listABValues);
        printValue(listBCValues);
        printValue(listCDValues);
        printValue(listADValues);

        // 第六部分数值获取（相位角）
        List<Float> listPhaseAngleValues = HexStrToFloat(resultLists.get(5));
        System.out.println("===============================");
        System.out.println("相位角Min\t相位角Max\t相位角");
        for (Float value : listPhaseAngleValues) {
            System.out.print(value + "\t");
        }
    }

    public StiffNessData getValues(List<List<String>> resultLists, StiffNessData stiffNessData) {

        // 第一部分数值转化
        List<String> onePartList = resultLists.get(0);

        int workAble = Integer.parseInt(onePartList.get(0), 16);
        int storeStatue = Integer.parseInt(onePartList.get(1), 16);

        List<String> oneHextoASCII = onePartList.subList(2, 5);
        List<String> typeASCIIList = HexStrToASCII(oneHextoASCII);

        int totalStatue = Integer.parseInt(onePartList.get(5));

        System.out.println("工位操作使能:" + workAble);
        System.out.println("存储状态:" + storeStatue);
        System.out.println("总状态:" + totalStatue);
        System.out.println("产品型号\t\t钢刻号\t\t二维码");
        for (String s : typeASCIIList) {
            System.out.print(s + "  ");
        }

        // 第二部分数值获取（AB）
        List<Float> listABValues = HexStrToFloat(resultLists.get(1));

        // 第三部分数值获取（BC）
        List<Float> listBCValues = HexStrToFloat(resultLists.get(2));

        // 第四部分数值获取（CD）
        List<Float> listCDValues = HexStrToFloat(resultLists.get(3));

        // 第五部分数值获取（AD）
        List<Float> listADValues = HexStrToFloat(resultLists.get(4));

        printValue(listABValues);
        printValue(listBCValues);
        printValue(listCDValues);
        printValue(listADValues);

        // 第六部分数值获取（相位角）
        List<Float> listPhaseAngleValues = HexStrToFloat(resultLists.get(5));
        System.out.println("===============================");
        System.out.println("相位角Min\t相位角Max\t相位角");
        for (Float value : listPhaseAngleValues) {
            System.out.print(value + "\t");
        }

        return stiffNessData;
    }

    /**
     * 16进制转化为浮点数
     */
    public static List<Float> HexStrToFloat(List<String> hexStrList) {
        List<Float> floatList = new ArrayList<>();

        for (String hexStr : hexStrList) {
            long longValue = Long.parseLong(hexStr, 16);
            float v = Float.intBitsToFloat((int) longValue);
//            DecimalFormat decimalFormat = new DecimalFormat("0.00");
            floatList.add(v);
        }

        return floatList;
    }

    /**
     * 16进制转化为ASCII
     */
    public static List<String> HexStrToASCII(List<String> hexStrList) {

        List<String> listASCII = new ArrayList<>();
        for (String hexStr : hexStrList) {
            StringBuilder output = new StringBuilder("");
            for (int i = 0; i < hexStr.length(); i += 2) {
                String str = hexStr.substring(i, i + 2);
                output.append((char) Integer.parseInt(str, 16));
            }
            listASCII.add(output.toString());
        }

        return listASCII;

    }

    /**
     * AB、BC、CD、AD 各刚度和间隙字符串值获取
     */
    public static ArrayList<String> twoPointValue(String str, int start, int end) {

        ArrayList<String> twoValueList = new ArrayList<>();
        for (int i = start; i < end; i += 8) {
            twoValueList.add(str.substring(i, i + 8));
        }
        return twoValueList;
    }

    //TODO
    /**
     * 钢刻号分析 (项目代号、日期、工位号)
     */
    public static List<String> steelMarkingAnalysis(String str){
        List<String> resultList = new ArrayList<>();


        return resultList;
    }

    /**
     * 打印测试（数值比对）
     */
    public static void printValue(List<Float> list) {
        System.out.println("===============================");
        System.out.println("刚度Min\t刚度Max\tCW  \tCCW \t间隙Min\t间隙Max\tCW  \tCCW \tresult");
        for (Float value : list) {
            System.out.print(value + "\t");
        }
    }

}
